/**
    ******************************************************************************
    * @file    async_cond_queue.c
    * @author  debian
    * @version V1.0.0
    * @date    2020-07-29
    * @brief   互斥+信号量
    ******************************************************************************
    * @attention
    *
    *
    ******************************************************************************
    */ 

/* Includes ------------------------------------------------------------------*/
#include "async_queue_interner.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>

/** @addtogroup DataStruct_Driver
    * @{
    */

/** @addtogroup async_cond_queue
    * @{
    */

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/


/** @defgroup async_cond_queue_Exported_Functions async_cond_queue Exported Functions
    * @{
    */

/** @defgroup async_cond_queue_Exported_Functions_Group1 Initialization and deinitialization functions
    *  @brief    Initialization and Configuration functions
    *
@verbatim    
    ===============================================================================
                ##### Initialization and deinitialization functions #####
    ===============================================================================
    [..]
        This section provides functions allowing to initialize and de-initialize the async_cond_queue
        to be ready for use.
 
@endverbatim
    * @{
    */ 
async_queue_t *async_cond_queue_creat(int size);
int async_cond_queue_push_tail(async_queue_t *async_queue, task_t *t);
task_t *async_cond_queue_pop_head(async_queue_t *async_queue, int timeout);
int async_cond_queue_pop_free(task_t* t);
int async_cond_queue_destroy(void);


async_queue_op_t async_cond_op =
{
    .name = "cond",
    .create = async_cond_queue_creat,
    .push = async_cond_queue_push_tail,
    .pop = async_cond_queue_pop_head,
    .task_free = async_cond_queue_pop_free
};

/**
    * @brief  创建async_cond_queue对象
    * @param  
    * @retval 
    */ 
    async_queue_t *async_cond_queue_creat(int size)
    {
        async_queue_t *async_queue = malloc(sizeof(async_queue_t));
        if(async_queue == NULL) {
            printf("async_queue is NULL\n");
            return NULL;
        }
        
        async_queue->q = queue_creat(size);
        if(async_queue->q == NULL) {
            printf("async_queue->q is NULL\n");
            return NULL;
        }
        pthread_mutex_init(&async_queue->mutex, NULL);
        pthread_cond_init(&async_queue->cond, NULL);

        async_queue->wait_thread = 0;

        return async_queue;
    }

    int async_cond_queue_push_tail(async_queue_t *async_queue, task_t *t)
    {
        if(!queue_is_full(async_queue->q)) {
            pthread_mutex_lock(&async_queue->mutex);
            queue_push_tail(async_queue->q, t);

            if(async_queue->wait_thread > 0) {
                pthread_cond_signal(&async_queue->cond);
            }
            pthread_mutex_unlock(&async_queue->mutex);

            return 0;
        }

        return -1;
    }


    task_t *async_cond_queue_pop_head(async_queue_t *async_queue, int timeout)
    {
        task_t *task = NULL;
        struct timeval now;
        struct timespec outtime;

        pthread_mutex_lock(&async_queue->mutex);
        if(queue_is_empty(async_queue->q)) {
            async_queue->wait_thread++;
            gettimeofday(&now, NULL);
            if (now.tv_usec + timeout > 1000)
            {
                outtime.tv_sec = now.tv_sec + 1;
                outtime.tv_nsec = ((now.tv_usec + timeout) % 1000) * 1000;
            }
            else
            {
                outtime.tv_sec = now.tv_sec;
                outtime.tv_nsec = (now.tv_usec + timeout) * 1000;
            }

            pthread_cond_timedwait(&async_queue->cond, &async_queue->mutex, &outtime);
            async_queue->wait_thread--;
        }
        
        task = queue_pop_head(async_queue->q);
        pthread_mutex_unlock(&async_queue->mutex);

        return task;
    }

    int async_cond_queue_pop_free(task_t* t)
    {
        free(t);
        return 0;
    }

/**
    * @brief  销毁async_cond_queue对象
    * @param  
    * @retval 
    */ 
    int async_cond_queue_destroy(void)
    {
        return 0;
    }
    
/**
    * @}
    */

/** @defgroup async_cond_queue_Exported_Functions_Group2 operation functions 
    *  @brief   operation functions
    *
@verbatim   
    ===============================================================================
                        ##### operation functions #####
    ===============================================================================
    [..]
        This subsection provides a set of functions allowing to manage the async_cond_queue.

@endverbatim
    * @{
    */

        /* 操作函数写在这里 */

    /**
    * @}
    */


/**
    * @}
    */

/**
    * @}
    */

/**
    * @}
    */

/************************ (C) 2020 HOME 深圳龙华 *****END OF FILE****/

